package com.abc.fast.server.user.service.impl;

import com.abc.fast.common.constant.CacheConstants;
import com.abc.fast.common.domain.enums.CommonErrorEnum;
import com.abc.fast.common.domain.enums.CommonStatusEnum;
import com.abc.fast.common.domain.model.LoginUser;
import com.abc.fast.common.exception.BusinessException;
import com.abc.fast.common.utils.AssertUtil;
import com.abc.fast.common.utils.RedisUtil;
import com.abc.fast.common.utils.SecurityUtil;
import com.abc.fast.security.context.AuthenticationContextHolder;
import com.abc.fast.common.domain.entity.User;
import com.abc.fast.server.user.service.IPermsService;
import com.abc.fast.server.user.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 用户验证处理
 * @Author LiJunXi
 * @Date 2024-03-01 17:11
 */
@Slf4j
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    // 最多密码错误重试3次
    private static Integer maxCount = 3;
    // 错误上限等待时间
    public static final int RETRY_TIME = 30;


    @Autowired
    private IUserService userService;

    @Autowired
    private IPermsService permsService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 检验用户状态
        User user = userService.selectByUsername(username);
        AssertUtil.isNotEmpty(user, "用户不存在");
        AssertUtil.equal(user.getStatus(), CommonStatusEnum.NORMAL.getStatus(), "用户已经禁用");
        // 检验密码
        validate(user);
        return createLoginUser(user);
    }

    public UserDetails createLoginUser(User user) {
        return new LoginUser(user.getId(), user, permsService.getPermission(user.getId()));
    }

    private void validate(User user) {
        Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
        String username = usernamePasswordAuthenticationToken.getName();
        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
        // 检验错误次数
        String key = getRetryKey(username);
        Integer count = RedisUtil.get(key, Integer.class);
        if (Objects.isNull(count)){
            count = 0;
        } else if (count >= maxCount){
            throw new BusinessException(CommonErrorEnum.RETRY_COUNT);
        }
        // 检验密码
        if (!SecurityUtil.matchesPassword(password, user.getPassword())){
            count = count + 1;
            RedisUtil.set(key, count, RETRY_TIME, TimeUnit.SECONDS);
            throw new BusinessException("账号或者密码错误");
        }
        // 清除登录错误次数缓存
        clearLoginCache(key);
    }

    private void clearLoginCache(String key) {
        if (RedisUtil.hasKey(key)) {
            RedisUtil.del(key);
        }
    }

    private String getRetryKey(String username) {
        return CacheConstants.getKey(CacheConstants.PWD_ERR_CNT_KEY, username);
    }
}
